package com.xnyy.lottery.service;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xnyy.lottery.common.exception.CustomException;
import com.xnyy.lottery.config.AppConfig;
import com.xnyy.lottery.domain.dto.DataDTO;
import com.xnyy.lottery.domain.entity.Member;
import com.xnyy.lottery.domain.entity.ParkingSpace;
import com.xnyy.lottery.domain.entity.Region;
import com.xnyy.lottery.domain.entity.RegisterRecord;
import com.xnyy.lottery.domain.entity.TNumber;
import com.xnyy.lottery.domain.entity.Ticket;
import com.xnyy.lottery.domain.mapper.MemberMapper;
import com.xnyy.lottery.domain.mapper.TNumberMapper;
import com.xnyy.lottery.domain.mapper.TicketMapper;
import com.xnyy.lottery.util.CopyUtils;
import com.xnyy.lottery.util.ExcelUtil;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;

/**
 * @description:
 * @auther: Administrator
 * @date: 2022/9/17 08:57
 */
@AllArgsConstructor
@Service
public class TicketService extends ServiceImpl<TicketMapper, Ticket> {
    private final MemberMapper memberMapper;
    private final TNumberMapper tNumberMapper;
    private final TicketMapper ticketMapper;
    private final RegionService regionService;
    private final Random random = new Random();
    //所有列
    private final List<DataDTO> dataList = new ArrayList<>();
    //生成序号
    private final Map<String, List<Integer>> numberMap = new HashMap<>();

    @Transactional(rollbackFor = Exception.class)
    public void init() {
        if (!memberMapper.exists(null)) {
            List<DataDTO> dataDTOList = ExcelUtil.importExcel(ResourceUtil.getStream(AppConfig.getProfile()), 0, 1, DataDTO.class);
            dataDTOList.forEach(dataDTO -> memberMapper.insert(CopyUtils.copy(dataDTO, Member.class)));
        }
        if (!tNumberMapper.exists(null)) {
            memberMapper.selectList(null).stream().collect(groupingBy(Member::getRegion, counting()))
                    .forEach(
                            (k, v) -> this.initNumber(k, v).forEach(tNumberMapper::insert)
                    );
        }

        dataList.addAll(
                memberMapper.selectList(
                        Wrappers.lambdaQuery(Member.class)
                                .eq(Member::getStatus, 0)
                ).stream().map(member -> CopyUtils.copy(member, DataDTO.class)).collect(Collectors.toList())
        );
        numberMap.putAll(
                tNumberMapper.selectList(
                        Wrappers.lambdaQuery(TNumber.class)
                                .eq(TNumber::getStatus, 0)
                ).stream().collect(groupingBy(TNumber::getRegion, mapping(TNumber::getSerialNumber, toList())))
        );

        for (Region region : regionService.findAll()) {
            if (!this.lambdaQuery().eq(Ticket::getRegion, region.getName()).exists()) {
                ticketMapper.insert(new Ticket(null, 0, region.getName()));
            }
        }
        //X 为未知区域
        if (!this.lambdaQuery().eq(Ticket::getRegion, Region.X).exists()) {
            ticketMapper.insert(new Ticket(null, 0, Region.X));
        }
    }

    public List<TNumber> initNumber(String region, Long max) {
        List<TNumber> list = new ArrayList<>();
        for (int i = 0; i < max; i++) {
            TNumber tNumber = new TNumber();
            tNumber.setRegion(region);
            tNumber.setStatus(0);
            tNumber.setSerialNumber(i + 1);
            list.add(tNumber);
        }
        return list;
    }

    /**
     * 生成序号
     *
     * @param registerRecord
     * @return
     */
    public void generate(RegisterRecord registerRecord) {
        String region = registerRecord.getRegion();
        Integer sortNum;
        if (StrUtil.isBlank(region)) {
            String queryRegion = Region.X;
            sortNum = ticketMapper.getNextNum(queryRegion);
            if (sortNum == null || ticketMapper.updateSerialNumber(queryRegion, 1) <= 0) {
                throw new CustomException("生成序号失败！！");
            }
            String serialNumber = getFormatNumber(sortNum);
            String barCode = StrUtil.trimToEmpty(registerRecord.getRegion()) + serialNumber;
            registerRecord.setSerialNumber(serialNumber);
            registerRecord.setBarCode(barCode);
            return;
        }
        if (!numberMap.containsKey(region)) {
            throw new CustomException("生成序号失败");
        }

        List<Integer> numberList = numberMap.get(region);
        if (numberList.isEmpty()) {
            throw new CustomException("生成序号失败！！");
        }
        sortNum = numberList.get(random.nextInt(numberList.size()));
        if (sortNum == null) {
            throw new CustomException("生成序号失败！！");
        }
        numberList.remove(sortNum);
        TNumber tNumber = new TNumber();
        tNumber.setStatus(1);
        tNumberMapper.update(tNumber, Wrappers.lambdaUpdate(TNumber.class).eq(TNumber::getRegion, region).eq(TNumber::getSerialNumber, sortNum));
        String serialNumber = getFormatNumber(sortNum);
        String barCode = StrUtil.trimToEmpty(registerRecord.getRegion()) + serialNumber;
        registerRecord.setSerialNumber(serialNumber);
        registerRecord.setBarCode(barCode);
    }

    //获取格式化字符串
    private String getFormatNumber(Integer sortNum) {
        return String.format("%03d", sortNum);
    }

    @Transactional(rollbackFor = Exception.class)
    public DataDTO getData() {
        DataDTO data = null;
        if (!dataList.isEmpty()) {
            data = dataList.get(0);
        }
        if (data == null) {
            throw new CustomException("号源池已无号源");
        }
        dataList.remove(data);
        Member member = new Member();
        member.setId(data.getId());
        member.setStatus(1);
        if (memberMapper.updateById(member) != 1) {
            throw new CustomException("取号失败");
        }
        return data;
    }

    public List<ParkingSpace> selectParkingSpace(String barCode, List<ParkingSpace> parkingSpaceList) {
        int size = 5;
        //fixme 这里需要屏蔽
        List<ParkingSpace> list = new ArrayList<>();
        //打乱顺序
        Collections.shuffle(parkingSpaceList);
        list.addAll(parkingSpaceList.subList(0, Math.min(size, parkingSpaceList.size())));
        return list;
    }
}
